﻿using System;
using System.Collections.Specialized;
using System.Data;
using System.Data.Entity;
using Vowei.Data;
using Vowei.Data.Models;
using Vowei.Core.Models;
using Vowei.Data.Helpers;
using System.Linq;

namespace Vowei.Services.SharePoint
{
    public class TaskProvider // : IProvider
    {
        private IVoweiContext _context;
        private IUser _currentUser;
        private const string TASK_ID_NAME = "IdForOws";

        public TaskProvider(IVoweiContext context)
            : this(context, null)
        {
        }

        public TaskProvider(IVoweiContext context, IUser user)
        {
            _context = context;
            _currentUser = user;
        }

        private DataTable CreateTaskTable()
        {
            DataTable taskTable = new DataTable(ListType.Tasks.ToString());
            taskTable.Columns.Add(TASK_ID_NAME, typeof(int));
            taskTable.Columns.Add("Title", typeof(string));
            taskTable.Columns.Add("Description", typeof(string));
            taskTable.Columns.Add("OpenDate", typeof(DateTime));
            taskTable.Columns.Add("ClosedDate", typeof(DateTime));
            taskTable.Columns.Add("Reporter", typeof(string));
            taskTable.Columns.Add("AssignedTo", typeof(string));
            taskTable.Columns.Add("LastModifiedDate", typeof(DateTime));
            taskTable.Columns.Add("StartDate", typeof(DateTime));
            taskTable.Columns.Add("DueDate", typeof(DateTime));
            taskTable.Columns.Add("Priority", typeof(string));
            taskTable.Columns.Add("Progress", typeof(float));
            taskTable.Columns.Add("Status", typeof(string));
            taskTable.Columns.Add("MetaInfo", typeof(string));

            return taskTable;
        }

        public DataSet GetEmptyDataSet()
        {
            DataSet dataSet = new DataSet();
            dataSet.Tables.Add(CreateTaskTable());

            return dataSet;
        }

        public ListType GetProviderType(Guid ProviderID)
        {
            return ListType.Tasks;
        }

        private Task[] GetUpdateSinceTokenImpl(Guid projectId, ChangeKey changeKey)
        {
            var project = _context.Projects.Find(projectId);
            if (project == null)
                throw new InvalidOperationException(string.Format("找不到Id为{0}的项目！", projectId.ToString("B")));

            var criteria = new FilterCriteria()
            {
                ChangedAfter = changeKey == null ? (DateTime?)null : changeKey.ChangeTime
            };

            var allTasks = project.AllTasks(_context).MyByEmail(_currentUser).Search(criteria);
            return allTasks.ToArray();
        }

        public DataSet GetUpdatesSinceToken(Guid projectId, ChangeKey changeKey)
        {
            DataSet taskSet = new DataSet();
            DataTable taskTable = CreateTaskTable();
            var allTasks = GetUpdateSinceTokenImpl(projectId, changeKey);

            foreach (var task in allTasks)
            {
                // TODO: 在web这一层，最好只使用接口，IdForOws是针对Outlook整合的一个临时方案，需要考虑一个代码比较简洁的方案
                taskTable.Rows.Add(((Task)task).IdForOws, task.Title, task.Description, task.OpenDate, task.ClosedDate, task.Reporter, task.AssignedTo,
                    task.LastModified, task.StartDate, task.DueDate, task.Priority, task.Progress, task.Status);
            }

            taskSet.Tables.Add(taskTable);

            return taskSet;
        }

        public StringDictionary GetFieldMappingsForListType(ListType listType)
        {
            StringDictionary fileNames = new StringDictionary();
            fileNames.Add(TASK_ID_NAME, "ID");
            fileNames.Add("Title", "Title");
            fileNames.Add("Description", "Body");
            fileNames.Add("OpenDate", "Created");
            fileNames.Add("ClosedDate", "DateComplete");
            fileNames.Add("Reporter", "Author");
            fileNames.Add("AssignedTo", "AssignedTo");
            fileNames.Add("LastModifiedDate", "Modified");
            fileNames.Add("StartDate", "StartDate");
            fileNames.Add("DueDate", "DueDate");
            fileNames.Add("Priority", "Priority");
            fileNames.Add("Progress", "PercentComplete");
            fileNames.Add("Status", "Status");
            fileNames.Add("MetaInfo", "MetaInfo");

            return fileNames;
        }

        public DataRow GetSingleRow(int id)
        {
            DataTable taskTable = CreateTaskTable();
            DataRow dataRow = taskTable.NewRow();

            var task = (Task)_context.Tasks.Query.FirstOrDefault(t => ((Task)t).IdForOws == id);
            if (task == null)
            {
                return null;
            }

            dataRow[TASK_ID_NAME] = task.IdForOws;
            dataRow["Title"] = task.Title;
            if (task.Description == null)
            {
                dataRow["Description"] = DBNull.Value;
            }
            else
            {
                dataRow["Description"] = task.Description;
            }
            dataRow["OpenDate"] = task.OpenDate;
            if (task.ClosedDate.HasValue)
            {
                dataRow["ClosedDate"] = task.ClosedDate.Value;
            }
            else
            {
                dataRow["ClosedDate"] = DBNull.Value;
            }
            dataRow["Reporter"] = task.Reporter;
            dataRow["AssignedTo"] = task.AssignedTo;
            dataRow["LastModifiedDate"] = task.LastModified;
            dataRow["StartDate"] = task.StartDate;
            dataRow["Progress"] = task.Progress;
            if (task.DueDate == null)
            {
                dataRow["DueDate"] = DBNull.Value;
            }
            else
            {
                dataRow["DueDate"] = task.DueDate;
            }
            if (task.Priority == null)
            {
                dataRow["Priority"] = DBNull.Value;
            }
            else
            {
                dataRow["Priority"] = task.Priority;
            }

            if (task.Status == null)
            {
                dataRow["Status"] = DBNull.Value;
            }
            else
            {
                dataRow["Status"] = task.Status;
            }

            return dataRow;
        }

        public DataRow Update(DataRow updateRow)
        {
            using (var context = new VoweiContextImpl())
            {
                DbSet<Task> tasks = context.FindTableByType<Task>();

                if (updateRow[TASK_ID_NAME] == null || updateRow[TASK_ID_NAME].ToString() == "") //New task, add it.
                {
                    Task newTask = new Task();
                    newTask.Title = updateRow["Title"] as string;
                    newTask.Description = updateRow["Description"] as string;
                    newTask.OpenDate = DateTime.Now;
                    if (updateRow["ClosedDate"] != null && updateRow["ClosedDate"].ToString() != "")
                    {
                        newTask.ClosedDate = (DateTime)updateRow["ClosedDate"];
                    }
                    newTask.Reporter = updateRow["Reporter"] as string;
                    newTask.AssignedTo = updateRow["AssignedTo"] as string;
                    newTask.LastModified = DateTime.Now;
                    newTask.StartDate = (DateTime)updateRow["StartDate"];
                    if (updateRow["DueDate"] != null && updateRow["DueDate"].ToString() != "")
                    {
                        newTask.DueDate = (DateTime)updateRow["DueDate"];
                    }
                    newTask.Priority = updateRow["Priority"] as string;
                    if (updateRow["Progress"] != null && updateRow["Progress"].ToString() != "")
                    {
                        newTask.Progress = (float)updateRow["Progress"];
                    }
                    newTask.Status = updateRow["Status"] as string;
                    newTask.Reporter = newTask.AssignedTo;
                    tasks.Add(newTask);
                    context.SaveChanges();

                    updateRow[TASK_ID_NAME] = newTask.IdForOws;
                    updateRow["LastModifiedDate"] = newTask.LastModified;
                    return updateRow;
                }

                //Update
                foreach (var task in tasks)
                {
                    if (task.IdForOws.Equals(updateRow[TASK_ID_NAME]))
                    {
                        task.Title = updateRow["Title"] as string;
                        task.Description = updateRow["Description"] as string;
                        if (updateRow["ClosedDate"] != null && updateRow["ClosedDate"].ToString() != "")
                        {
                            task.ClosedDate = (DateTime)updateRow["ClosedDate"];
                        }
                        task.Reporter = updateRow["Reporter"] as string;
                        task.AssignedTo = updateRow["AssignedTo"] as string;
                        task.LastModified = DateTime.Now;
                        task.StartDate = (DateTime)updateRow["StartDate"];
                        if (updateRow["DueDate"] != null && updateRow["ClosedDate"].ToString() != "")
                        {
                            task.DueDate = (DateTime)updateRow["DueDate"];
                        }
                        task.Priority = updateRow["Priority"] as string;
                        if (updateRow["Progress"] != null && updateRow["Progress"].ToString() != "")
                        {
                            task.Progress = (float)updateRow["Progress"];
                        }
                        task.Status = updateRow["Status"] as string;
                        task.Reporter = task.AssignedTo;

                        updateRow["LastModifiedDate"] = task.LastModified;
                        break;
                    }
                }

                context.SaveChanges();

                return updateRow;
            }
        }

        public void Delete(int id)
        {
            var task = _context.Tasks.Query.FirstOrDefault(t => ((Task)t).IdForOws == id);
            _context.Tasks.Remove(task);
            _context.SaveChanges();
        }
    }
}
